#!/usr/bin/perl -w   ; useful for syntax checking
package clreqd_modules;

use strict;
use cldb;
use Config;
use mnttab;

sub unmount_app_fs {
my %ARGS=@_;

	local $SIG{CHLD}='DEFAULT';
	my $FS=undef; my $LV=undef; my $VG=undef;
	$FS=$ARGS{FS} if(exists($ARGS{FS}) && defined($ARGS{FS}));
	$VG=$ARGS{VG} if(exists($ARGS{VG}) && defined($ARGS{VG}));
	$LV=$ARGS{LV} if(exists($ARGS{LV}) && defined($ARGS{LV}));

	my $APP=$ARGS{APPLICATION};
	my $TIMEOUT=10;

	if(exists($ARGS{TIMEOUT}) && $ARGS{TIMEOUT} =~ /^\d+$/) {
		$TIMEOUT=$ARGS{TIMEOUT};
	}

	#################################################################
	# Open a connection to the database to read in file system	#
	# details [then close it].					#
	#################################################################

	my $CLDB=new cldb("$::ENV{TRUECL_CFG}/config.db");
	if(!defined($CLDB)) {
		return "ERROR - Unable to config to 'config' database.";
	}
	my $res=$CLDB->get_rows("SELECT * FROM application_fs WHERE name = '$APP';");
	$CLDB->disconnect;
	if(!defined($res->[0]->{mountpnt})) {
		return "OK 0 0";
	}
	my $starttime=time;
	my $cnt=0; my $failed=0; my $total=0;
	my $fuser;
	if(-x "/sbin/fuser") {
		$fuser="/sbin/fuser";
	} elsif(-x "/usr/bin/fuser") {
		$fuser="/usr/bin/fuser";
	} elsif(-x "/usr/sbin/fuser") {
		$fuser="/usr/sbin/fuser";
	}
	my $umount;
	if(-x "/bin/umount") {
		$umount="/bin/umount";
	} elsif(-x "/sbin/umount") {
		$umount="/sbin/umount";
	} else {
		$umount="/usr/sbin/umount";
	}
	my $kill;
	if(-x "/bin/kill") {
		$kill="/bin/kill";
	} else {
		$kill="/usr/bin/kill";
	}
	my $os=$Config{'osname'};
	
	my $cmd;
	while(1) {
		my $mnttab=new mnttab;
		my $attempts=0;
		my $crec;
		for $crec (@$res) {
			if(defined($VG) && defined($LV)) {
				if(! ($VG eq $crec->{vg} && $LV eq $crec->{lv})) {
					next;
				}
			} elsif(defined($FS) && defined($crec->{mountpnt}) && $crec->{mountpnt} ne $FS) {
				next;
			}
			#########################################################
			# If the fstype eq NONE then we don't actually do 	#
			# anything since this is a raw logical volume entry.	#
			#########################################################
			if($crec->{fstype} eq "NONE") {
				next;
			}
			if(defined($FS) && $crec->{mountpnt} ne $FS) {
				next;
			}
			if(! $mnttab->is_mounted($crec->{mountpnt})) {
				next;
			}

			#########################################################
			# Let mnttab define the device that the specified 	#
			# directory is mounted on..				#
			#########################################################
			my $dev=$mnttab->mount_dev($crec->{mountpnt});
			if(!defined($dev)) {
				::warning("Device for $crec->{mountpnt} not found - ignoring.");
				next;
			}

			#################################################
			# First time around just attempt unmount.	#
			# Then up until TIMEOUT send kill -1 to any	#
			# processes found, after that kill -9.		#
			#################################################
			$cmd="";
			if($total==0) {
				$cmd="";
			} elsif(time-$starttime<$TIMEOUT && defined($fuser)) {
				$cmd="$fuser ";
				if($os eq "linux") {
					$cmd.="-m $crec->{mountpnt} 2>/dev/null";
				} else {
					$cmd.=" $dev 2>/dev/null";
				}
			} else {
				if(defined($fuser)) {
					$cmd="$fuser -k ";
					if($os eq "linux") {
						$cmd.="-m $crec->{mountpnt} 2>/dev/null";
					} else {
						$cmd.=" $dev 2>/dev/null";
					}
				} elsif($Config{'osname'} eq "freebsd") {
					$cmd="$umount -f $crec->{mountpnt} 2>/dev/null";
				}
			}
			if(length($cmd)) {
				::msg("Running: $cmd");
				my $pids=`$cmd`;
				#########################################
				# Linux puts in the file in stdout, not	#
				# stderr so we've got to strip it out.	#
				#########################################
				if($os eq "linux") {
					my @D=split(/\s+/,$pids);
					$pids=join(" ",@D[1 .. $#D]);
				}
				chomp $pids;
				if(length($pids)) {
					::msg("Running: $kill $pids");
					system("$kill $pids 2>/dev/null");
				}
			}
			#################################################
			# Now attempt the unmount.			#
			#################################################
			$attempts++;
			::msg("Running: $umount $crec->{mountpnt}");
			system("$umount $crec->{mountpnt} >/dev/null 2>&1");
			if($?>>8==0) {
				$cnt++;
			} else {
				::msg("Failed to un-mount '$crec->{mountpnt} [device=$dev]'.");
			}
		}
		last if @$res == $cnt;
		if($attempts==0) {
			last;
		}
		$total++;
		select(undef,undef,undef,1);
		if(time-$starttime>$TIMEOUT+2) {
			::warning("Timeout occurred whilst performing un-mount!");
			last;
		}
	}

	# Double check to see if any still mounted ...
	my $mnttab=new mnttab;
	my $crec;
	$cnt=$failed=0;
	for $crec (@$res) {
		if(defined($FS) && $crec->{mountpnt} ne $FS) {
			next;
		}
		if($mnttab->is_mounted($crec->{mountpnt})) {
			$failed++;
		} else {
			$cnt++;
		}
	}
	return "OK $cnt $failed";
}

1;
